/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javaapplication2;

/**
 *
 * @author loc@
 */
import java.io.IOException;
import java.io.*;
import java.util.BitSet;


public class Tokenizer {
	private static final BitSet whiteSpace = new BitSet();
        private BufferedReader sarchivo;
        private int cont;

	static {
		whiteSpace.set(' ');
		whiteSpace.set('\t');
		whiteSpace.set('\r');
		whiteSpace.set('\f');
	}

	private static final BitSet single = new BitSet();

	static {
		single.set('!');
		single.set('%');
		single.set('^');
		single.set('&');
		single.set('*');
		single.set('(');
		single.set(')');
		single.set('-');
		single.set('+');
		single.set('=');
		single.set('[');
		single.set(']');
		single.set('{');
		single.set('}');
		single.set('|');
		single.set(':');
		single.set(';');
		single.set(',');
		single.set('.');
		single.set('<');
		single.set('>');
		single.set('?');
		single.set('~');
	}

	private PushbackReader reader;


	public Tokenizer(Reader reader) {
		this.reader = new PushbackReader(reader);
	}

	public Token next() throws IOException {
		skipWhitespace();
		int c = reader.read();
		if (c < 0)
			return new Token(Token.EOF);
		else if (c == '\n')
			return new Token(Token.EOL);
		else if (c == '\'' || c == '"')
			return munchString(c);
		else if (c == '/')
			return maybeComment();
		else if (single.get(c))
			return new Token(Token.SINGLE, String.valueOf((char) c));
		else {
			reader.unread(c);
			return parseWord();
		}
	}

	private void skipWhitespace() throws IOException {
		for (; ;) {
			int c = reader.read();
			if (c < 0) break;
			if (!whiteSpace.get(c)) {
				reader.unread(c);
				break;
			}
		}
	}

	private Token munchString(int delimiter) throws IOException {
		final int SCAN = 0;
		final int ESCAPE = 1;
		final int DONE = 2;

		StringBuilder result = new StringBuilder();
		result.append((char) delimiter);
		int state = SCAN;

			while (state != DONE) {
				int c = reader.read();
				if (c < 0)
					break;
				result.append((char) c);
				switch (state) {
				case SCAN:
					if (c == delimiter)
						state = DONE;
					else if (c == '\\')
						state = ESCAPE;
					break;
				case ESCAPE:
					state = SCAN;
					break;
				}
			}
		return new Token(Token.STRING, result.toString());
	}

	private Token maybeComment() throws IOException {
		int c = reader.read();
		if (c == '/') {
			// Single line comment
			StringBuilder result = new StringBuilder();
			result.append("//");
			for (; ;) {
				c = reader.read();
				if (c < 0)
					break;
				else if (c == '\n') {
					reader.unread(c);
					break;
				}
				result.append((char) c);
			}
			return new Token(Token.COMMENT, result.toString());
		} else if (c == '*') {
			// C-style multiline comment
			StringBuilder result = new StringBuilder();
			result.append("/*");
			final int SCAN = 0;
			final int STAR = 1;
			final int DONE = 2;
			int state = SCAN;
			while (state != DONE) {
				c = reader.read();
				if (c < 0)
					state = DONE;
				else
					result.append((char) c);
				switch (state) {
				case SCAN:
					if (c == '*')
						state = STAR;
					break;
				case STAR:
					if (c == '/')
						state = DONE;
					else if (c != '*')
						state = SCAN;
					break;
				case DONE:
					break;
				}
			}
			return new Token(Token.COMMENT, result.toString());
		} else {
			if (c >= 0)
				reader.unread(c);
			return new Token(Token.SINGLE, "/");
		}
	}

	private Token parseWord() throws IOException {
		StringBuilder result = new StringBuilder();
		for (; ;) {
			int c = reader.read();
			if (c < 0)
				break;
			if (whiteSpace.get(c) || c == '\n' || single.get(c)) {
				reader.unread(c);
				break;
			}
			result.append((char) c);
		}
		return new Token(Token.WORD, result.toString());
	}
        
        
        public Tokenizer(String archivo) throws IOException  
        {
                sarchivo = new BufferedReader(new FileReader(archivo));
                cont=0;                    
        }
        
        public Token getToken(int linea) throws IOException  
        { 
            cont=0;    
            String s="";
                
                while(cont!=linea)
                {
                    if (( s = sarchivo.readLine()) != null){
                        cont++;
                    }
                    else
                        break;
                }
                return new Token(linea,s);
        }            
}
